import os, sys
import time
import cPickle as pickle
import ConfigParser
import twitter
import simplejson

try:
    import keychain
    use_keychain = True
    kc = keychain.Keychain()
except ImportError, e:
    use_keychain = False

def get_tmp_dir():
    if os.environ.has_key("TMPDIR"):
        return os.environ.get("TMPDIR")
    else:
        return "/tmp"

RC="~/.clitterrc"
PUBLIC_HISTORY="~/.clitter_public"
FRIENDS_HISTORY="~/.clitter_friends"
RUN_FILE = os.path.join(get_tmp_dir(), "clitter-daemon.run")

def load_conf(opts):
    cp = ConfigParser.ConfigParser()
    # if there is no .rc, make one
    try:
        os.stat( os.path.expanduser(RC) )
    except:
        fp = open(os.path.expanduser(RC),'w')
        fp.write("[Clitter]")
        fp.close()
    cp.read(os.path.expanduser(RC))
    return ClitterConf(cf=cp,options=opts)

def load_history(cf):
    return {"public":History(PUBLIC_HISTORY, cf),
            "friends":History(FRIENDS_HISTORY, cf)}

def load_api(cf):
    return twitter.Api(username=cf.username,
            password=cf.password, input_encoding=cf.encoding)

class ClitterConf(object):
    """
    An object to encapsulate various configuration options for Clitter.
    """
    SECTION = "Clitter"
    PARAMETERS = ('username','password','frequency','archive','channel','encoding','force','search')

    def __init__(self, *args, **kwargs):
        # set up some defaults
        self.frequency = None
        self.archive = 1000
        self.channel = "public"
        self.encoding = "utf-8"
        self.force = False
        self.search = None

        self._conf_file = kwargs.get('cf')
        self._options   = kwargs.get('options')
        for param in self.PARAMETERS:
            try:
                setattr(self,param,self._conf_file.get(self.SECTION,param))
            except Exception, e:
                pass
        self._parse_options(self._options)
        if not hasattr(self,"username") or not hasattr(self,"password"):
            creds = False
            if use_keychain:
                creds = kc.getinternetpassword('twitter.com')
                if creds:
                    self.username = creds['account']
                    self.password = creds['password']
            
            if not use_keychain or not creds:
                self.username = raw_input("Please enter your username: ")
                self.password = raw_input("Please enter your password: ")
        
        # if there is no frequency set or passed in lets only consume
        # 25% of the allotted checks per hour
        if self.frequency is None:
            try:
                self.frequency = int(60 / int(self.get_rate_limit()/4))
            except ZeroDivisionError:
                # default to 15 minutes if all else fails
                self.frequency = 15 

    def _parse_options(self, options):
        for param in self.PARAMETERS:
            try:
                v = getattr(options,param)
                if v is not None:
                    setattr(self, param, v)
            except Exception, e:
                pass

    def get_rate_limit(self):
        "This will check the current rate limit set forth by Twitter"
        resource = "http://twitter.com/account/rate_limit_status.json"
        # this is cheating and bad...
        return simplejson.loads(load_api(self)._FetchUrl(resource)).get("remaining_hits")


    def get_frequency(self):
        "Return frequency in seconds"
        return int(self.frequency) * 60

    def get_archive(self):
        "Return max archive size"
        return int(self.archive)

class History(object):
    """
    Holds a list of tweets
    """
    def __init__(self, file_name, conf):

        self.file_name = os.path.expanduser(file_name)
        self.last_update = os.stat(self.file_name)[-2] #mtime
        self.max_tweets = conf.get_archive()
        self.frequency = conf.get_frequency()
        self.tweets = self._load_from_file() or []
    
    def _load_from_file(self):
        try:
            f = open(self.file_name)
            tweets = pickle.load(f)
            return tweets
        except Exception, e:
            print "Could not load tweets from %s: %s" % (self.file_name,e)
            return []
        finally:
            f.close()

    def _save_to_file(self):
        try:
            f = open(self.file_name, 'w')
            pickle.dump(self.tweets,f)
        except Exception, e:
            print "Could not save tweet states in %s: %s" % (self.file_name,e)
        finally:
            f.close()

    def add(self, states):
        """
        Add a list of states to this history. The history will be truncated
        if the overall length exceeds the archive value set in the users rc.
        """
        if not states:
            return
        # weed out dupes
        current = [ct.id for ct in self.tweets]
        self.tweets.extend([t for t in states if t.id not in current])
        # sort and truncate
        self.sort()
        self.tweets = self.tweets[:self.max_tweets]
        self._save_to_file()

    def sort(self, by="id"):
        """
        Sorts the history by a parameter.
        """
        decorated = [(getattr(t,by),t) for t in self.tweets]
        decorated.sort()
        self.tweets = [t[1] for t in decorated]
        self.tweets.reverse()

    def get(self, count=20, search=None):
        if search:
            candidates = [t for t in self.tweets if search in t.text]
            return candidates[:count][::-1]
        else:
            return self.tweets[:count][::-1]

    def update(self):
        "Returns whether or not this should be updated"
        now = time.time()
        return (now > (self.last_update + self.frequency))


